//
// winter - Direct2D GUI framework.
// Copyright (C) 2009 Aleksandar Dezelin 
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef FACTORY_HOST_H
#define FACTORY_HOST_H

#pragma once
#include "canvas.h"
#include "com_qi_ptr.h"
#include "noncopyable.h"
#include "winter_assert.h"
#include <d2d1.h>
#include <exception>

#pragma comment(lib, "d2d1.lib")

namespace winter {
namespace platform {
namespace canvas {

using namespace winter::canvas;
using namespace winter::platform::com;

class factory_host : public services::noncopyable {
public:
  factory_host() {
    create_factory();
  }

  ID2D1DCRenderTarget* create_dc_render_target(
    const render_target_properties& properties) const {
    D2D1_RENDER_TARGET_PROPERTIES rtp;
    com_qi_ptr<ID2D1DCRenderTarget> render_target;
    create_d2d1_rt_properties(properties, rtp);
    HRESULT hr = _factory->CreateDCRenderTarget(&rtp, &render_target);
    WINTER_ASSERT(SUCCEEDED(hr));
    return render_target.detach();
  }

  ID2D1HwndRenderTarget* create_hwnd_render_target(
    const render_target_properties& properties,
    const hwnd_render_target_properties& hwnd_properties) const {
    D2D1_RENDER_TARGET_PROPERTIES rtp;
    D2D1_HWND_RENDER_TARGET_PROPERTIES hwnd_rtp;
    com_qi_ptr<ID2D1HwndRenderTarget> render_target;
    create_d2d1_rt_properties(properties, rtp);
    create_d2d1_hwnd_rt_properties(hwnd_properties, hwnd_rtp);
    HRESULT hr = _factory->CreateHwndRenderTarget(&rtp, &hwnd_rtp, &render_target);
    WINTER_ASSERT(SUCCEEDED(hr));
    return render_target.detach();
  }

private:
  void create_factory() {
    HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 
      &_factory);
    WINTER_ENSURE(SUCCEEDED(hr));
  }

  static void create_d2d1_rt_properties(
    const render_target_properties& properties,
    D2D1_RENDER_TARGET_PROPERTIES& rtp) {
    memset(&rtp, 0, sizeof(rtp));
    rtp.dpiX = properties.get_dpi_x();
    rtp.dpiY = properties.get_dpi_y();
    rtp.minLevel = static_cast<D2D1_FEATURE_LEVEL>(
      properties.get_feature_level());
    rtp.pixelFormat.alphaMode = static_cast<D2D1_ALPHA_MODE>(
      properties.get_pixel_format().get_alpha_mode());
    rtp.pixelFormat.format = static_cast<DXGI_FORMAT>(
      properties.get_pixel_format().get_format());
    rtp.type = static_cast<D2D1_RENDER_TARGET_TYPE>(properties.get_type());
    rtp.usage = static_cast<D2D1_RENDER_TARGET_USAGE>(properties.get_usage());
  }

  static void create_d2d1_hwnd_rt_properties(
    const hwnd_render_target_properties& properties,
    D2D1_HWND_RENDER_TARGET_PROPERTIES& rtp) {
    memset(&rtp, 0, sizeof(rtp));
    rtp.hwnd = properties.get_hwnd();
    rtp.pixelSize.height = static_cast<uint32_t>(
      properties.get_pixel_size().get_height());
    rtp.pixelSize.width = static_cast<uint32_t>(
      properties.get_pixel_size().get_width());
    rtp.presentOptions = static_cast<D2D1_PRESENT_OPTIONS>(
      properties.get_present_options());
  }

  com_qi_ptr<ID2D1Factory> _factory;
};

}
}
}

#endif // FACTORY_HOST_H
